package slw.controls
{
	import flash.events.MouseEvent;
	import flash.utils.getDefinitionByName;
	
	import slw.events.LabelButtonEvent;
	
	/**
	 * ButtonGroup
	 * 按钮组类,当按钮加入ButtonGroup中时,toggle属性将被设置为true，<br/>
	 * 当groupMode="multiple"时按钮组可以有多个按钮同时被选中，<br/>
	 * 当groupMode="single"时按钮组具有互斥性，每次只有1个按钮被选中
	 * @author ddx<br/>
	 * 2011-7-30
	 *
	 */
	public class ButtonGroup
	{
		/**
		 * "multiple",多选模式，多个按钮可以同时被选中，多用于CheckBox组
		 */
		public static const MULTIPLE:String="multiple";
		/**
		 * "single",单选模式，按钮组中的按钮具有互斥性，每次只有1个按钮被选中
		 */
		public static const SINGLE:String="single";
		//按钮数组，按钮数据数组
		private var _buttons:Array=[];
		private var _datas:Array=[];
		//組模式，按钮的data属性保存的数据的属性，按钮类或类字符串
		private var _groupMode:String;
		private var _dataField:String="data";
		private var _classField:*=LabelButton;
		//最后一个选中的按钮
		private var _selectedButton:LabelButton;
		
		/**
		 * 构造函数 
		 * @param datas:Array=null 用于创建按钮组的数据数组，默认将数据元素的label属性赋值给按钮的label属性，
		 * 将数据元素的data(可通过dataField属性设置为其它属性)属性赋值给按钮的data属性,按钮的toggle属性(可切换选中与未选中状态)自动设置为true
		 * @param groupMode:String=SINGLE 按钮选择模式，可能的值为:<br/>
		 * <ul>
		 * <li>ButtonGroup.SINGLE:"single",单选模式，按钮组中的按钮具有互斥性，每次只有1个按钮被选中,默认值<br/>
		 * <li>ButtonGroup.MULTIPLE:"multiple",多选模式，多个按钮可以同时被选中，多用于CheckBox组<br/>
		 * </ul>
		 * 
		 */		
		public function ButtonGroup(datas:Array=null,groupMode:String=SINGLE)
		{
			this.groupMode=groupMode;
			this.datas=datas;
		}
		
		/*
		-----------------------------------
		setters getters
		-----------------------------------
		*/
		//
		/**
		 * 按钮组数据数组，更改时重新创建所有按钮组，并关联最新数据，之前创建的按钮组将被销毁(调用destroy()方法)
		 * @param value:Array 通常元素为Object对象:{label:xxx,data:xxx},将数据元素的label属性赋值给按钮的label属性，
		 * 将数据元素的data(可通过dataField属性设置为其它属性)属性赋值给按钮的data属性
		 * 
		 */		
		public function set datas(value:Array):void{
			if(_datas==value) return;
			
			for(var j:int=0;j<_buttons.length;j++){
				if(_buttons[j]!=null){
					_buttons[j].removeEventListener(MouseEvent.CLICK,clickHandler);
					
					if(_buttons[j].hasOwnProperty("destroy")){
						_buttons[j].destroy();
					}
				}
			}
			
			_datas=[];
			_buttons=[];
			if(value==null||value.length==0) _datas=value;
			
			for(var i:int=0;i<value.length;i++){
				addButtonByData(value[i]);
			}
		}
		//
		/**
		 * 按钮组数据数组，更改时重新创建所有按钮组，并关联最新数据，之前创建的按钮组将被销毁(调用destroy()方法)
		 * @param value:Array 通常元素为Object对象:{label:xxx,data:xxx},将数据元素的label属性赋值给按钮的label属性，将数据元素的data(可通过dataField属性设置为其它属性)属性赋值给按钮的data属性
		 * 
		 */
		public function get datas():Array{
			return _datas;
		}
		//
		/**
		 * 按钮选择模式，应在设置datas属性前设置此属性，否则若已有选择项，将在选择项被改变时才会生效，可能的值为:<br/>
		 * <ul>
		 * <li>ButtonGroup.SINGLE:"single",单选模式，按钮组中的按钮具有互斥性，每次只有1个按钮被选中,默认值<br/>
		 * <li>ButtonGroup.MULTIPLE:"multiple",多选模式，多个按钮可以同时被选中，多用于CheckBox组<br/>
		 * </ul>
		 * @param value:String
		 * 
		 */		
		public function set groupMode(value:String):void{
			if(_groupMode==value) return;
			
			var $modes:Array=[MULTIPLE,SINGLE];
			if($modes.indexOf(value)==-1) throw new Error("groupMode可能的值为以下之一:"+$modes);
			
			_groupMode=value;
		}
		//
		/**
		 * 按钮选择模式，应在设置datas属性前设置此属性，否则若已有选择项，将在选择项被改变时才会生效，可能的值为:<br/>
		 * <ul>
		 * <li>ButtonGroup.SINGLE:"single",单选模式，按钮组中的按钮具有互斥性，每次只有1个按钮被选中,默认值<br/>
		 * <li>ButtonGroup.MULTIPLE:"multiple",多选模式，多个按钮可以同时被选中，多用于CheckBox组<br/>
		 * </ul>
		 * @param value:String
		 * 
		 */	
		public function get groupMode():String{
			return _groupMode;
		}
		//
		/**
		 * 按钮组中的所有按钮 
		 * @return 
		 * 
		 */		
		public function get buttons():Array{
			return _buttons;
		}
		//
		/**
		 * 按钮组中的按钮数量 
		 * @return 
		 * 
		 */		
		public function get numButtons():int{
			return _buttons.length;
		}
		//
		/**
		 * 最后被选中的按钮,主要用于单选时访问选中按钮项 
		 * @return 
		 * 
		 */		
		public function get selectedButton():LabelButton{
			return _selectedButton;
		}
		//
		/**
		 * 最后被选中的按钮数据,主要用于单选时访问选中按钮项数据  
		 * @return 
		 * 
		 */		
		public function get selectedData():Object{
			return _selectedButton.data;
		}
		//
		/**
		 * 最后被选中的按钮索引,主要用于单选时访问选中按钮项索引  
		 * @param value:int
		 * 
		 */		
		public function set selectedIndex(value:int):void{
			if(this.selectedIndex==value) return;
			
			if(_buttons!=null&&_buttons.length!=0&&_buttons[value]!=null){
				resetSelected();
				LabelButton(_buttons[value]).selected=true;
				_selectedButton=_buttons[value];
			}else if(value==-1){
				resetSelected();
			}
		}
		//
		/**
		 * 最后被选中的按钮索引,主要用于单选时访问选中按钮项 
		 * @param value:int
		 * 
		 */	
		public function get selectedIndex():int{
			return _buttons.indexOf(_selectedButton);
		}
		//
		/**
		 * 被选中的按钮数组，当选择模式为单选时，数组元素只有1个，主要用于多选时访问所有选中按钮项
		 * @return 
		 * 
		 */		
		public function get selectedButtons():Array{
			var $result:Array=[];
			for(var i:int=0;i<_buttons.length;i++){
				if(LabelButton(_buttons[i]).selected)
					$result.push(_buttons[i]);
			}
			return $result;
		}
		//
		/**
		 * 被选中的按钮索引数组，当选择模式为单选时，数组元素只有1个，主要用于多选时访问所有选中按钮项 
		 * @param value:Array 设置为null或[]时,重置所有按钮项为未选中
		 * 
		 */		
		public function set selectedIndices(value:Array):void{
			if(this.selectedIndices==value) return;
			
			if(value==null||value.length==0)
				resetSelected();
			
			resetSelected();
			for(var i:int=0;i<value.length;i++){
				if(_buttons!=null&&_buttons.length!=0&&_buttons[i]!=null){
					if(_groupMode==SINGLE)
						resetSelected();
					
					LabelButton(_buttons[i]).selected=true;
				}
			}
		}
		//
		/**
		 * 被选中的按钮索引数组，当选择模式为单选时，数组元素只有1个，主要用于多选时访问所有选中按钮项 
		 * @param value:Array 设置为null或[]时,重置所有按钮项为未选中
		 * 
		 */
		public function get selectedIndices():Array{
			var $result:Array=[];
			for(var i:int=0;i<_buttons.length;i++){
				if(LabelButton(_buttons[i]).selected)
					$result.push(i);
			}
			return $result;
		}
		//
		/**
		 * 被选中的按钮数据数组，当选择模式为单选时，数组元素只有1个，主要用于多选时访问所有选中按钮项 
		 * @return 
		 * 
		 */		
		public function get selectedDatas():Array{
			var $result:Array=[];
			for(var i:int=0;i<_buttons.length;i++){
				if(LabelButton(_buttons[i]).selected)
					$result.push(LabelButton(_buttons[i]).data);
			}
			return $result;
		}
		//
		/**
		 * datas属性数组元素中Object对象保存到按钮data属性中的属性值，更改时所有按钮重新关联数据
		 * @param value:String
		 * 
		 */		
		public function set dataField(value:String):void{
			if(_dataField==value) return;
			
			_dataField=value;
			
			for(var i:int=0;i<_buttons.length;i++){
				if(LabelButton(_buttons[i]).hasOwnProperty("data")&&_datas[i]!=null)
					LabelButton(_buttons[i]).data=_datas[i][_dataField];
			}
		}
		//
		//
		/**
		 * datas属性数组元素中Object对象保存到按钮data属性中的属性值，更改时所有按钮重新关联数据
		 * @param value:String
		 * 
		 */
		public function get dataField():String{
			return _dataField;
		}
		//
		/**
		 * 用于创建按钮的类或类字符串，更改时重新创建所有按钮组，并关联最新数据，之前创建的按钮组将被销毁(调用destroy()),
		 * 当使用类字符串时，必须使用完全限定名称，如:"flash.display.Sprite"，并且在此之前此类有实例存在(调用过构造函数)，否则报未定义 
		 * @param value:* String或Class对象
		 * 
		 */		
		public function set classField(value:*):void{
			if(_classField==value) return;
			if(!(value is Class)&&!(value is String))
				throw new Error("classField属性应为String或Class对象");
			
			_classField=value;
			
			var $datas:Array=_datas.concat();
			this.datas=$datas;
		}
		//
		/**
		 * 用于创建按钮的类或类字符串，更改时重新创建所有按钮组，并关联最新数据，之前创建的按钮组将被销毁(调用destroy()),
		 * 当使用类字符串时，必须使用完全限定名称，如:"flash.display.Sprite"，并且在此之前此类有实例存在(调用过构造函数)，否则报未定义 
		 * @param value:* String或Class对象
		 * 
		 */
		public function get classField():*{
			return _classField;
		}
		/*
		-----------------------------------
		public  methods
		-----------------------------------
		*/
		//
		/**
		 * 根据数据添加一个按钮(classField属性定义的类)添加至按钮组末尾,此方法相当于调用addButton()+addData(),按钮的toggle属性(可切换选中与未选中状态)自动设置为true
		 * @param data:Object 通常为Object对象:{label:xxx,data:xxx},将数据元素的label属性赋值给按钮的label属性，
		 * 将数据元素的data(可通过dataField属性设置为其它属性)属性赋值给按钮的data属性
		 * 
		 */		
		public function addButtonByData(data:Object):void{
			if(data==null) throw new Error("data参数不能为"+data);
			
			var $c:Class;
			if(_classField is Class){
				$c=_classField;
			}else if(_classField is String){
				$c=getDefinitionByName(_classField) as Class;
			}
			
			var $instance:*=new $c();
			if(data.hasOwnProperty("label"))
				$instance.label=data.label;
			if(data.hasOwnProperty(_dataField))
				$instance.data=data[_dataField];
			
			addButton($instance);
			_datas.push(data);
		}
		//
		/**
		 * 将一个按钮(继承自LabelButton类)添加至按钮组末尾，配合addData()方法进行数据关联,按钮的toggle属性(可切换选中与未选中状态)自动设置为true
		 * @param button:LabelButton
		 * 
		 */		
		public function addButton(button:LabelButton):void{
			if(button.hasOwnProperty("toggle"))
				button.toggle=true;
			button.addEventListener(MouseEvent.CLICK,clickHandler);
			
			_buttons.push(button);
		}
		//
		/**
		 * 将数据关联至按钮组中的最后一个按钮,配合addButton()方法使用
		 * @param data:Object 通常元素为Object对象:{label:xxx,data:xxx},将数据元素的label属性赋值给按钮的label属性，
		 * 将数据元素的data(可通过dataField属性设置为其它属性)属性赋值给按钮的data属性
		 * 
		 */		
		public function addData(data:Object):void{
			_datas.push(data);
			
			if(data.hasOwnProperty("label")&&_buttons[_datas.length-1]!=null)
				LabelButton(_buttons[_datas.length-1]).label=data.label;
			if(data.hasOwnProperty(_dataField)&&_buttons[_datas.length-1]!=null)
				LabelButton(_buttons[_datas.length-1]).data=data[_dataField];
		}
		//
		/**
		 * 将一个按钮(继承自LabelButton类)添加至按钮组index索引处，配合addDataAt()方法进行数据关联,按钮的toggle属性(可切换选中与未选中状态)自动设置为true 
		 * @param button:LabelButton
		 * @param index:int
		 * 
		 */		
		public function addButtonAt(button:LabelButton,index:int):void{
			if(button.hasOwnProperty("toggle"))
				button.toggle=true;
			button.addEventListener(MouseEvent.CLICK,clickHandler);
			
			_buttons.splice(index,0,button);
			
			for(var i:int=0;i<_buttons.length;i++){
				if(_buttons[i]==null&&_datas[i]==null){
					_buttons.splice(i,1);
					_datas.splice(i,1);
					i--;
				}
			}
		}
		//
		/**
		 * 将数据关联至按钮组中的index索引处的按钮, 配合addButtonAt()方法使用
		 * @param data:Object 通常为Object对象:{label:xxx,data:xxx},将数据元素的label属性赋值给按钮的label属性，
		 * 将数据元素的data(可通过dataField属性设置为其它属性)属性赋值给按钮的data属性
		 * @param index:int
		 * 
		 */		
		public function addDataAt(data:Object,index:int):void{
			if(data.hasOwnProperty("label")&&_buttons[index]!=null)
				LabelButton(_buttons[index]).label=data.label;
			if(data.hasOwnProperty(_dataField)&&_buttons[index]!=null)
				LabelButton(_buttons[index]).data=data[_dataField];
			
			_datas.splice(index,0,data);
		}
		//
		/**
		 * 将按钮从组中删除，但并不销毁(不调用destroy()方法)，未从显示列表删除
		 * @param button:LabelButton
		 * 
		 */		
		public function removeButton(button:LabelButton):void{
			if(_buttons==null) return;
			
			var $index:int=_buttons.indexOf(button);
			if($index!=-1) removeButtonAt($index);
		}
		//
		/**
		 * 将index索引处的按钮从组中删除，但并不销毁(不调用destroy()方法)，未从显示列表删除 
		 * @param index:int
		 * 
		 */		
		public function removeButtonAt(index:int):void{
			if(_buttons==null) return;
			
			if(_selectedButton!=null&&_buttons.indexOf(_selectedButton)!=-1){
				_selectedButton=null;
			}
			
			if(_buttons[index]!=null){
				_buttons[index].removeEventListener(MouseEvent.CLICK,clickHandler);
				_buttons.splice(index,1);
			}
			
			if(_datas==null) return;
			if(_datas[index]!=null) _datas.splice(index,1);
		}
		//
		/**
		 * 获取索引处的按钮 
		 * @param index:int
		 * @return LabelButton
		 * 
		 */		
		public function getButtonAt(index:int):LabelButton{
			return _buttons[index];
		}
		//
		/**
		 * 获取按钮的索引 
		 * @param button:LabelButton
		 * @return int
		 * 
		 */		
		public function getButtonIndex(button:LabelButton):int{
			return _buttons.indexOf(button);
		}
		/*
		-----------------------------------
		private  methods
		-----------------------------------
		*/
		//点击按钮
		private function clickHandler(e:MouseEvent):void{
			switch(_groupMode){
				case MULTIPLE:
					if(LabelButton(e.target).selected){
						e.target as LabelButton;
					}else{
						_selectedButton=null;
					}
					break;
				case SINGLE:
					if(_selectedButton!=null) 
						_selectedButton.selected=false;
					_selectedButton=e.target as LabelButton;
					_selectedButton.selected=true;
					break;
			}
		}
		//重置选中项
		private function resetSelected():void{
			for(var i:int=0;i<_buttons.length;i++){
				if(_buttons!=null&&_buttons.length!=0&&_buttons[i]!=null)
					LabelButton(_buttons[i]).selected=false;
			}
		}
	}
}